package com.ant.storage.service.impl;


import com.ant.storage.common.ResultCode;
import com.ant.storage.common.ResultVo;
import com.ant.storage.dto.InventoryDto;
import com.ant.storage.excel.InventoryCensusExecl;
import com.ant.storage.handler.AntException;
import com.ant.storage.mapper.CommodityMapper;
import com.ant.storage.mapper.InventoryLogMapper;
import com.ant.storage.mapper.InventoryMapper;
import com.ant.storage.pojo.*;
import com.ant.storage.service.ICommodityService;
import com.ant.storage.service.IInventoryService;
import com.ant.storage.service.IWarehouseService;
import com.ant.storage.vo.CommodityVo;
import com.ant.storage.vo.InventoryCensusVo;
import com.ant.storage.vo.PurchaseVo;
import com.ant.storage.vo.WarehouseAndCommodityVo;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author melon
 * @since 2022-03-16
 */
@Service
public class InventoryServiceImpl extends ServiceImpl<InventoryMapper, Inventory> implements IInventoryService {

    @Autowired
    private IWarehouseService warehouseService;

    @Autowired
    private ICommodityService commodityService;

    @Autowired(required = false)
    CommodityMapper commodityMapper;

    @Autowired(required = false)
    InventoryMapper inventoryMapper;

    @Resource
    public InventoryLogMapper inventoryLogMapper;

    @Autowired
    public ServletContext servletContext;

    @Override
    public PageInfo<Inventory> querylist(InventoryDto inventoryDto) {
        try {
            PageHelper.startPage(inventoryDto.getPageIndex(), inventoryDto.getPageSize());
            List<Inventory> commodityList = this.baseMapper.selectList(null);
            List<Inventory> inventoryList = commodityList.stream().map(item -> {
                //查詢在那个仓库
                Warehouse warehouseList = warehouseService.getOne(new QueryWrapper<Warehouse>().eq("id",
                        item.getWarehouseId()));
                item.setWarehouseList(warehouseList);
                //查詢商品
                Commodity commodity = commodityService.getOne(new QueryWrapper<Commodity>().eq("commodity_id",
                        item.getWarehouseId()));
                item.setCommodity(commodity);
                return item;
            }).collect(Collectors.toList());
            PageInfo<Inventory> pageInfo = new PageInfo<>(inventoryList);
            return pageInfo;
        } catch (Exception e) {
            throw new AntException(ResultCode.BODY_NOT_MATCH);
        }
    }

    @Override
    public boolean commodityInventoryJudge(Integer commodity_id, Integer warehouse_id, Integer commodity_inventory) {
        QueryWrapper<Inventory> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("commodity_id", commodity_id).eq("commodity_id", commodity_id);

        double abs = Math.abs(this.getOne(queryWrapper).getGoodsAmount().subtract(new BigDecimal(commodity_inventory)).doubleValue());
        if(abs>0){
            return  true;
        }
        return  false;
       // return this.getOne(queryWrapper).getGoodsAmount() >= new BigDecimal(commodity_inventory);
    }

    @Override
    public void stockSubtract(Integer warehouse_id, Integer commodity_id, Integer commodity_out_quantity) {
        inventoryMapper.stockSubtract(warehouse_id, commodity_id, commodity_out_quantity);
    }

    @Override
    public void stockAdd(Integer warehouse_id, Integer commodity_id, Integer commodity_enter_quantity) {
        inventoryMapper.stockAdd(warehouse_id, commodity_id, commodity_enter_quantity);
    }

    @Override
    public List<CommodityVo> findWarehouseAndInventory(Integer id) {
        return inventoryMapper.findWarehouseAndInventory(id);
    }

    @Override
    public List<InventoryCensusVo> censusList(InventoryDto dto) {
        if(dto.getTime()!=null && dto.getTime().size()>0){
            String stats=dto.getTime().get(0)+" 00:00:00";
            String end=dto.getTime().get(1)+" 23:59:59";
            ArrayList<String> time = new ArrayList<>();
            time.add(stats);
            time.add(end);
            dto.setTime(time);
        }
        List<InventoryCensusVo> list = this.baseMapper.findCensus(dto);
        return list;
//        synchronized (this) {
//            List<InventoryCensusVo> list = inventoryMapper.findCensusList(dto);
//            List<InventoryLog> logList = this.baseMapper.findAllbalanceQuantity(dto.getWarehouseId(),
//                    dto.getPreviousTime());
//            list.stream().map(item -> {
//                // 上期结存数量
//                //long previous_total_amount_outbound =
//               // logList.stream().filter(i-> i.getInventoryId().equals(item.getId())).filter(g -> "1".equals(g.getStockState())).map(k -> Long.valueOf(k.getGoodsAmount())).mapToLong(Long::longValue).sum();
//
//               // long previous_total_amount_enter =
//               // logList.stream().filter(i-> i.getInventoryId().equals(item.getId())).filter(g -> "2".equals(g.getStockState())).map(k -> Long.valueOf(k.getGoodsAmount())).mapToLong(Long::longValue).sum();
//                String previous_total_amount_outbound = this.baseMapper.balanceQuantity(1, item.getId(), dto.getPreviousTime());
//                String previous_total_amount_enter = this.baseMapper.balanceQuantity(2, item.getId(), dto.getPreviousTime());
//                Double previous_total_amount = Double.valueOf(previous_total_amount_outbound) - Double.valueOf(previous_total_amount_enter);
//                item.setPrevious_period_balance_totals(previous_total_amount.toString());
//
//                // 上期结存数量 TotalPrice
////                logList.stream().filter(i-> i.getInventoryId().equals(item.getId())).filter(g -> "1".equals(g.getStockState()))
////                                .forEach(g-> g.getGoodsPrice().multiply(BigDecimal.valueOf( Double.parseDouble(g.getGoodsAmount()))));
////                 logList.stream().filter(i-> i.getInventoryId().equals(item.getId()))
////                        .filter(g -> "2".equals(g.getStockState()))
////                        .forEach(g-> g.getGoodsPrice().multiply(BigDecimal.valueOf( Double.parseDouble(g.getGoodsAmount()))));
////
//                BigDecimal previous_total_price_outbound = this.baseMapper.balancePrice(1, item.getId(),dto.getPreviousTime());
//                BigDecimal previous_total_price_enter = this.baseMapper.balancePrice(2, item.getId(),dto.getPreviousTime());
//                BigDecimal previous_total_price = previous_total_price_outbound.subtract(previous_total_price_enter);
//
//                item.setPrevious_period_balance_total_prices(previous_total_price.setScale(5,
//                        BigDecimal.ROUND_HALF_UP));
//
//                // 本期收入数量
//                String income_total_amount = this.baseMapper.balanceQuantity(1, item.getId(), dto.getTime());
//                item.setIncomeTotal(income_total_amount);
//
//                // 本期收入价格 TotalPrice
//                BigDecimal income_total_price = this.baseMapper.balancePrice(1, item.getId(), dto.getTime());
//                item.setIncomeTotalPrice(income_total_price.setScale(5, BigDecimal.ROUND_HALF_UP));
//
//                // 本期发出数量
//                String issue_total_amount = this.baseMapper.balanceQuantity(1, item.getId(), dto.getTime());
//                item.setIssue_totals(issue_total_amount);
//
//                // 本期发出价格 TotalPrice
//                BigDecimal issue_total_price = this.baseMapper.balancePrice(1, item.getId(), dto.getTime());
//                item.setIssue_total_prices(issue_total_price.setScale(5, BigDecimal.ROUND_HALF_UP));
//
//                // 本期结存数量
//                Double current_total_amount =
//                        Double.valueOf(previous_total_amount) - (Double.valueOf(income_total_amount) + Double.valueOf(issue_total_amount));
//                item.setCurrent_period_balance_totals(current_total_amount < 0 ? "0" : current_total_amount.toString());
//                // 本期期结存价格 TotalPrice
//                BigDecimal current_total_price =
//                        previous_total_price.subtract(income_total_price.add(issue_total_price));
//                current_total_price = current_total_price.compareTo(BigDecimal.ZERO) < 0 ? new BigDecimal("0") :
//                        current_total_price;
//                item.setCurrent_period_balance_total_prices(current_total_price.setScale(5, BigDecimal.ROUND_HALF_UP));
//
//                return item;
//            }).collect(Collectors.toList());
//
//            return list;
//        }
    }

    /**
     * import
     *
     * @param file
     * @throws IOException
     */
    @Override
    public ResultVo uploadInventory(MultipartFile file) throws IOException {
        //定义员工POJO类

        //解析出来的封装好要返回的对象
        List<Inventory> inventoryList = new ArrayList<>();
        try {
            //插入数据库时，需要日期格式转换
            SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
            if (file.isEmpty()) {
                //先判断客户端上传的excel有没有效
                throw new RuntimeException("文件错误");
            }
            // 获取文件的后缀名
            String filename = file.getOriginalFilename();
            //
            Workbook workbook;
            if (filename.endsWith("xls")) {
                workbook = new HSSFWorkbook(file.getInputStream());
            } else if (filename.endsWith("xlsx")) {
                workbook = new XSSFWorkbook(file.getInputStream());
            } else {
                return ResultVo.fail("文件格式错误!");
            }
            // 判断第一页是否为空
            if (workbook.getSheetAt(0) != null) {
                for (int rowNumofSheet = 1; rowNumofSheet <= workbook.getSheetAt(0).getLastRowNum(); rowNumofSheet++) {
                    if (null != workbook.getSheetAt(0).getRow(rowNumofSheet)) {
                        //定义行，并赋值
                        Row aRow = workbook.getSheetAt(0).getRow(rowNumofSheet);
                        Inventory inventory = new Inventory();
                        System.out.println(aRow.getLastCellNum());
                        for (int cellNumofRow = 0; cellNumofRow < aRow.getLastCellNum(); cellNumofRow++) {
                            //读取rowNumOfSheet值所对应行的数据
                            //获得行的列数
                            Cell xCell = aRow.getCell(cellNumofRow);
                            Object cell_val;

                            if (cellNumofRow == 0) {
                                if (xCell != null && !xCell.toString().trim().isEmpty()) {
                                    cell_val = xCell.getStringCellValue();
                                    if (cell_val != null) {
                                        int temp = (Integer) cell_val;
                                        inventory.setWarehouseId(temp);
                                    }
                                }
                            }
                            if (cellNumofRow == 1) {
                                if (xCell != null && !xCell.toString().trim().isEmpty()) {
                                    cell_val = xCell.getStringCellValue();
                                    if (cell_val != null) {
                                        String value = (String) cell_val;
                                        Commodity one = commodityService.getOne(new QueryWrapper<Commodity>().eq(
                                                "commodity_bar_code", value));
                                        //                                        Integer commodityId = null;
                                        //                                        if (one == null) {
                                        //                                            Commodity commodity = new
                                        //                                            Commodity();
                                        //                                            commodity.setCityId(1);
                                        //                                            commodity.setCommodityName(value);
                                        //                                            commodity.setCommodityType
                                        //                                            ("BGP" + commodityMapper
                                        //                                            .selectLastID());
                                        //                                            commodity.setCreationBy("admin");
                                        //                                            commodity.setCreationTime(new
                                        //                                            Date());
                                        //                                            commodityService.save(commodity);
                                        //                                            commodityId = commodity
                                        //                                            .getCommodityId();
                                        //                                        } else {
                                        //                                            commodityId = one
                                        //                                            .getCommodityId();
                                        //                                        }
                                        inventory.setCommodityId(one.getCommodityId());
                                    }
                                }
                            }
                            if (cellNumofRow == 2) {
                                if (xCell != null && !xCell.toString().trim().isEmpty()) {
                                    cell_val = xCell.getStringCellValue();
                                    if (cell_val != null) {
                                        String temp = (String) cell_val;
                                        inventory.setGoodsAmount(new BigDecimal(temp));
                                    }
                                }
                            }
                            if (cellNumofRow == 3) {
                                if (xCell != null && !xCell.toString().trim().isEmpty()) {
                                    cell_val = xCell.getStringCellValue();
                                    if (cell_val != null) {
                                        BigDecimal temp = (BigDecimal) cell_val;
                                        inventory.setGoodsPrice(temp);
                                    }
                                }
                            }
                        }
                        inventoryList.add(inventory);
                        inventoryMapper.insert(inventory);
                    }
                }
                return ResultVo.success("导入成功");
            } else {
                return ResultVo.success("第一页EXCL无数据！");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }


    //        FileInputStream inputStream = new FileInputStream(file);
    //        // 2.通过poi解析流 HSSFWorkbook 处理流得到的对象中 就封装了Excel文件所有的数据
    //        XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
    //        // 3.从文件中获取表对象  getSheetAt通过下标获取
    //        //        HSSFSheet sheet = workbook.getSheetAt(0);   不支持用HSSF 所以换成了XSSF
    //        XSSFSheet sheet = workbook.getSheetAt(0);
    //        // 4.从表中获取到行数据  从第二行开始 到 最后一行  getLastRowNum() 获取最后一行的下标
    //        int lastRowNum = sheet.getLastRowNum();
    //
    //        for (int i = 1; i <= lastRowNum; i++) {
    //            //通过下标获取行
    //            XSSFRow row = sheet.getRow(i);
    //            // 从行中获取数据
    //            /**
    //             * getNumericCellValue() 获取数字
    //             * getStringCellValue 获取String
    //             */
    //            String commodityName = row.getCell(0).getStringCellValue();
    //            Commodity commodity = new Commodity();
    //            commodity.setCommodityBarCode("BGP" + this.baseMapper.selectLastID());
    //            commodity.setCommodityName(commodityName);
    //            commodity.setCreationTime(new Date());
    //            bjddwService.insertBjddw(bjddw);


    public String selectLastID() {
        return commodityMapper.selectLastID();
    }

    @Override
    public Commodity SaveCommodity(Commodity commodity) {
        commodity.setCommodityBarCode("BGP" + selectLastID());
        commodity.setCreationBy("admin");
        commodity.setCreationTime(new Date());
        commodityService.save(commodity);
        return commodity;
    }

    @Override
    public Commodity selectCommodity(String name) {
        return commodityService.getOne(new QueryWrapper<Commodity>().eq(
                "commodity_name", name));
    }

    /**
     * 日志记录
     */
    @Override
    public void insertLog(Inventory inventory) {
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        InventoryLog log = new InventoryLog();
        log.setWarehouseId(inventory.getWarehouseId());
        log.setInventoryId(inventory.getId());
        log.setGoodsAmount(inventory.getGoodsAmount().toString()); // 入库实际数量
        log.setGoodsPrice(inventory.getGoodsPrice()); // 入库实际数量
        log.setStockState(1); // 入库
        log.setRemark("系统导入数据入库"); // 入库
        log.setPurchaseOrdersId(inventory.getId());
        log.setCreatorBy(userInfo.getNameId().toString());
        log.setCreationTime(new Date());
        inventoryLogMapper.insert(log);
    }

    @Override
    public void inventoryUpate(String total_num, Inventory one) {
        Inventory inventory = new Inventory();
        inventory.setGoodsAmount(new BigDecimal(total_num).setScale(2,BigDecimal.ROUND_HALF_UP));
        inventory.setGoodsPrice(price(one.getId()) == null ? one.getGoodsPrice() : price(one.getId()));
        inventory.setId(one.getId());
        inventoryMapper.updateById(inventory);
    }

    @Override
    public Commodity getOneCommodityId(String codes) {
        Commodity commodity = commodityService.getOne(new QueryWrapper<Commodity>()
                .eq("commodity_bar_code", codes).eq("is_delete",1));
        return commodity;
    }

    /**
     * 计算价格
     *
     * @return
     */
    private BigDecimal price(Integer inventoryId) {
        List<InventoryLog> list = inventoryLogMapper.selectList(new QueryWrapper<InventoryLog>()
                .eq("inventory_id", inventoryId).eq("stock_state", 1));
        if (list.size() > 0) {
            int buySum =
                    list.stream().map(item -> Integer.valueOf(item.getGoodsAmount())).mapToInt(Integer::intValue).sum();
            double v =
                    list.stream().map(a -> new BigDecimal(String.valueOf(a.getGoodsAmount())).multiply(new BigDecimal(String.valueOf(a.getGoodsPrice())))).reduce(BigDecimal.ZERO, BigDecimal::add).doubleValue();
            BigDecimal divide = BigDecimal.valueOf(v).divide(BigDecimal.valueOf(buySum), 3, BigDecimal.ROUND_HALF_DOWN);
            return divide;
        }
        return null;
    }

    @Override
    public List<InventoryCensusExecl> exportCensus(Integer warehouseId, String commodityType,
                                                   List<String> previousTime, List<String> time) {
        // TODO 优化导出
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        String balanceNumber=  this.baseMapper.balanceNumber(userInfo.getCityId());
        List<InventoryCensusExecl> list = this.baseMapper.exportCensusList(warehouseId, commodityType,time,balanceNumber);
        return list;
    }


    @Override
    public InventoryCensusExecl exportCensusTotal(Integer warehouseId, List<String> previousTime, List<String> time) {
        return this.baseMapper.exportCensusTotal(warehouseId, previousTime, time);
    }

    @Override
    public List<InventoryCensusVo> balanceList(InventoryDto dto) {
        // TODO 优化导出
//        if(dto.getTime()!=null && dto.getTime().size()>0){
//            String stats=dto.getTime().get(0)+" 00:00:00";
//            String end=dto.getTime().get(1)+" 23:59:59";
//            ArrayList<String> time = new ArrayList<>();
//            time.add(stats);
//            time.add(end);
//            dto.setTime(time);
//        }
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        dto.setBalanceNumber(this.baseMapper.balanceNumber(userInfo.getCityId()));
        List<InventoryCensusVo> list = this.baseMapper.findBalanceList(dto);
        return list;
    }

    @Override
    public List<CommodityVo> findWarehouseCarInventory(Integer id) {
        return inventoryMapper.findWarehouseCarInventory(id);
    }

    @Override
    @Transactional(rollbackFor =Exception.class )
    public ResultVo findInventoryAdjust(WarehouseAndCommodityVo dto) {
        try {
            Inventory inventory = inventoryMapper.selectOne(new QueryWrapper<Inventory>()
                    .eq("id", dto.getInventoryId()));

            if(inventory==null){
                throw new AntException(ResultCode.FAILURE.getCode(), "库存不存在");
            }

            BigDecimal GoodsAmount=new BigDecimal("0");
            //计算总的数量
            if(dto.getStockState()==1){
                GoodsAmount = inventory.getGoodsAmount()
                        .add(dto.getCommodityAmount());
            }else{
                GoodsAmount = inventory.getGoodsAmount()
                        .subtract(dto.getCommodityAmount());
            }
            GoodsAmount.setScale(2, BigDecimal.ROUND_HALF_UP);

            Inventory inventory_new = new Inventory();
            inventory_new.setGoodsAmount(GoodsAmount);
            inventory_new.setId(inventory.getId());
            inventoryMapper.updateById(inventory_new);

            insertLoginLog(inventory.getId(),dto);
            return ResultVo.success("操作成功");
        }catch (Exception e) {
            throw new AntException(ResultCode.FAILURE.getCode(), "操作失败");
        }
    }

    private BigDecimal CalculateUnitPrices(Inventory inventory, PurchaseVo vo) {
        // 计算库存单价
        BigDecimal GoodsAmount = inventory.getGoodsAmount();
        BigDecimal GoodsPrice = inventory.getGoodsPrice();
        BigDecimal unitPrice1 = GoodsAmount.multiply(GoodsPrice).setScale(5, BigDecimal.ROUND_HALF_UP);
        // 计算入库单价
        BigDecimal CommodityAmount = new BigDecimal(vo.getCommodityNumber());
        BigDecimal CommodityPrice = vo.getCommodityPrice();
        BigDecimal unitPrice2 = CommodityAmount.multiply(CommodityPrice).setScale(5, BigDecimal.ROUND_HALF_UP);

        BigDecimal totalPrice = unitPrice1.add(unitPrice2);
        BigDecimal totalAmout = GoodsAmount.add(CommodityAmount);
        BigDecimal unitPrice = totalPrice.divide(totalAmout, 5, BigDecimal.ROUND_HALF_UP);
        return unitPrice;
    }
    /**
     * 添加入库日志记录
     */
    public void insertLoginLog(Integer inventoryId,WarehouseAndCommodityVo vo) {
        UserInfo userInfo = (UserInfo) servletContext.getAttribute("userInfo");
        InventoryLog  one= inventoryLogMapper.selectOneLast(inventoryId);
        one.setGoodsAmount(vo.getCommodityAmount().toString());
        one.setRemark(vo.getRemark());
        one.setStockState(vo.getStockState());
        one.setCreatorBy(userInfo.getNameId().toString());
        one.setCreationTime(new Date());
        one.setReimburse(3);
        inventoryLogMapper.insert(one);
    }
}
